package cnu.cse.crawler.main;

import java.net.CookieHandler;
import java.net.CookieManager;
import java.sql.SQLException;

import cnu.cse.crawler.xedata.XeBoard;
import cnu.cse.crawler.xedata.XeDocument;
import cnu.cse.crawler.manager.ConnectionManager;
import cnu.cse.crawler.manager.DatabaseManager;
import cnu.cse.crawler.manager.FileDownloadManager;
import cnu.cse.crawler.manager.PageParsingManager;
import cnu.cse.crawler.utils.InstallCert;

public class CnuCseCrawlerMain 
{
	private static final String websiteId = "{user id}";
	private static final String websitePassword = "{user password}";
	private static final String databaseUrl = "jdbc:mysql://localhost:3306/{databasename}?characterEncoding=UTF-8";
	private static final String databaseId = "root";
	private static final String databasePassword = "{root password]";
	
	private static final String baseHttpUrl = "http://computer.cnu.ac.kr";
	private static final String baseHttpsUrl = "https://computer.cnu.ac.kr";
	private static final String loginPagePath = "/_login";
	private static final String noticeBoardPath = "/notice.brd";
	
	private static final String attachedBinariesAbsolutePath = "C:\\APM_Setup\\htdocs\\xe\\files\\attach\\binaries";
	private static final String attachedImagesAbsolutePath = "C:\\APM_Setup\\htdocs\\xe\\files\\attach\\images";
	private static final String attachedBinariesRelativePath = "./files/attach/binaries";
	private static final String attachedImagesRelativePath = "./files/attach/images";
	
	private static final Long noticeBoardModuleSerial = 100L;
	
	public static void main(String[] args) throws Exception
	{
		/****************************** MEMO ******************************/
		
		//
		//
		//
		
		
		
		
		
		
		/****************************** Initialization Phase ******************************/
				
		///// IP#1. install the SSL certificate
		
		InstallCert installCert = new InstallCert();
		String[] arg = new String[1];
		arg[0] = "computer.cnu.ac.kr";
		installCert.install(arg);
				
		
		
		///// IP#2. set a system property to specify the location of the trust store
		
		System.setProperty( "javax.net.ssl.trustStore", "jssecacerts");
				
		
		
		// IP#3. initialize manager classes and CookieHandler
		
		ConnectionManager conMgr = ConnectionManager.getInstance();
		PageParsingManager parMgr = PageParsingManager.getInstance();
		FileDownloadManager fdMgr = FileDownloadManager.getInstance();
		DatabaseManager dbMgr = DatabaseManager.getInstance();
	
		fdMgr.initAttachedFileAbsolutePath(attachedBinariesAbsolutePath, attachedImagesAbsolutePath);
		dbMgr.initAttachedFileRelativePath(attachedBinariesRelativePath, attachedImagesRelativePath);		
		dbMgr.connectDatabase(databaseUrl, databaseId, databasePassword);
				
		CookieHandler.setDefault(new CookieManager());
				
		
		
		// IP#4. send a HTTPS GET request to know the login form
		
		String loginPageFullUrl = baseHttpsUrl + loginPagePath;
		String loginPage = null;
		String loginParameters = null;
		
		System.out.print("sending HTTPS GET request (" + loginPageFullUrl + ") ..... ");
		loginPage = conMgr.httpsGetRequest(loginPageFullUrl);
		
		if (loginPage != null)
		{
			System.out.println("OK");
			
			System.out.print("\t extracting login form and making a parameter list  ..... ");			
			loginParameters = conMgr.getLoginFormParameterList(loginPage, websiteId, websitePassword);
			System.out.println("OK");
		}
		else
		{
			System.err.println("Failure");
		}
		
		System.out.println();
			
		
		
		// IP#5. send a HTTPS POST request for authentication
		
		String loginResult = null;
		
		System.out.print("sending HTTPS POST request (" + loginPageFullUrl + ") ..... ");
		loginResult = conMgr.httpsPostRequestForLogin(loginPageFullUrl, loginParameters);
		
		if (loginResult != null)
		{
			System.out.println("OK");
		}
		else
		{
			System.err.println("Failure");
		}
		
		System.out.println();
		
		
		
		
		
				
		/****************************** Parsing Phase ******************************/
				
		// PP#1. create a XeBoard by parsing a HTML document (start page of the board)
		
		String noticeBoardFullUrl = baseHttpUrl + noticeBoardPath;
		String noticeBoardHtml = null;
		XeBoard noticeBoard = null;
		
		System.out.print("sending HTTP GET request to (" + noticeBoardFullUrl + ") ..... ");		
		noticeBoardHtml = conMgr.httpGetRequest(noticeBoardFullUrl);
		
		if (noticeBoardHtml != null)
		{
			System.out.println("OK");
			
			System.out.print("\t creating a XeBoard from a HTML document ..... ");
			noticeBoard = parMgr.createBoardFromBoardHtml(baseHttpUrl, noticeBoardPath, noticeBoardHtml);
			System.out.println("OK");
			System.out.println("\t\t - page count: " + noticeBoard.getPageCount());
		}
		else
		{
			System.err.println("Failure");
		}
		
		System.out.println();
		
		
		
		// PP#2. create skeleton XeDocuments by parsing the HTML documents (each page of the board) and inserts into the XeBoard
		
		int noticeBoardPageCount = noticeBoard.getPageCount();
		for (int i=0; i<noticeBoardPageCount; i++)
		{
			System.out.print("sending HTTP GET request to (" + baseHttpUrl + noticeBoard.getPagePath(i) + ") ..... ");
			String boardPageHtml = conMgr.httpGetRequest(baseHttpUrl + noticeBoard.getPagePath(i));
			if (boardPageHtml != null)
			{
				System.out.println("OK [" + (i+1) + "/" + noticeBoardPageCount + "]");
				
				System.out.print("\t inserting skeleton XeDocuments into a XeBoard .....");
				parMgr.addDocumentsOfEachPageIntoBoard(noticeBoard, boardPageHtml);
				System.out.println("OK");
			}
			else
			{
				System.err.println("Failure");
			}
		}
		
		System.out.println();
		
		
		
		// PP#3. insert web contents into the each XeDocument
		
		int noticeBoardDocumentCount = noticeBoard.getDocumentCount();
		for (int i=0; i<noticeBoardDocumentCount; i++)
		{
			System.out.print("sending HTTP-GET request to '" + noticeBoard.getDocument(i).getPath() + "' ..... ");
			String documentHtml = conMgr.httpGetRequest(baseHttpUrl + noticeBoard.getDocument(i).getPath());
			if (documentHtml != null)
			{
				System.out.println("OK [" + (i+1) + "/" + noticeBoardDocumentCount + "]");
				
				System.out.print("\t inserting web contents into a XeDocuments .....");
				parMgr.addContentsIntoDocument(noticeBoard.getDocument(i), documentHtml);
				System.out.println("OK");
			}
			else
			{
				System.err.println("Failure");
			}
		}
		
		System.out.println();
		
		
		
		
		
		
		/****************************** print a XeBoard and all XeDocuments ******************************/
		
		System.out.println("Basic Info =================================================================");
		System.out.println("\t Name: Notice Board");
		System.out.println("\t Base URL: " + noticeBoard.getBaseUrl());
		System.out.println("\t Path: " + noticeBoard.getPath());
		System.out.println("\t Page Count: " + noticeBoard.getPageCount());
		System.out.println("\t Real Page Count: " + noticeBoard.getRealPageCount());
		System.out.println("\t Document Count: " + noticeBoard.getDocumentCount());
		System.out.println("\t Real Document Count: " + noticeBoard.getRealDocumentCount());
		
		System.out.println("Page URLs  =================================================================");
		for (int i=0; i<noticeBoard.getRealPageCount(); i++)
		{
			System.out.println("\t * " + noticeBoard.getPagePath(i));
		}
		
		System.out.println("Documents  =================================================================");
		for (int i=0; i<noticeBoard.getDocumentCount(); i++)
		{
			XeDocument doc = noticeBoard.getDocument(i);
			System.out.println("\t Number: " + doc.getNumber());
			System.out.println("\t Path: " + doc.getPath());
			
			switch (doc.getType())
			{
				case XeDocument.TYPE_UNKNOWN:
					System.out.println("\t Type: Unknown");
					break;
				case XeDocument.TYPE_NOTICE:
					System.out.println("\t Type: Notice");
					break;
				case XeDocument.TYPE_LOCKED:
					System.out.println("\t Type: Completed");
					break;
				case XeDocument.TYPE_DELETED:
					System.out.println("\t Type: Deleted");
					break;
				case XeDocument.TYPE_NORMAL:
					System.out.println("\t Type: Normal");
					break;
				case XeDocument.TYPE_NEWEST:
					System.out.println("\t Type: Newest");
					break;
			}
						
			System.out.println("\t Title: " + doc.getTitle());
			System.out.println("\t Date: " + doc.getDate());
			System.out.println("\t Time: " + doc.getTime());
			System.out.println("\t Writer ID: " + doc.getWriterId());
			System.out.println("\t Writer Nickname: " + doc.getWriterNickname());
			System.out.println("\t Comment Count: " + doc.getCommentCount());
			System.out.println("\t Read Count: " + doc.getReadCount());
			System.out.println("\t Contents Summary: " + doc.getContentsSummary());
			System.out.println("\t IP Address: " + doc.getIpAddress());
			// System.out.println("\tContents: " + doc.getContents());
			
			if (doc.isAttachedFile() == true)
			{
				System.out.println("\t Have Attached File: true");
				for (int j=0; j<doc.getAttachedFileCount(); j++)
				{
					System.out.println("\t\t - File Name: " + doc.getAttachedFile(j).getSourceFileName());
					System.out.println("\t\t - File Path: " + doc.getAttachedFile(j).getSourceFilePath());
				}
			}
			else
			{
				System.out.println("\t Have Attached File: false");
			}
			
			System.out.println("----------------------------------------------------------------------------");
		}
		
		System.out.println("============================================================================");
		System.out.println();
		
		
		
		
		
		
		/****************************** Backup Phase ******************************/
		
		// BP#1. insert a XeBoard and its XeDocuments into the relation database
		
		try
		{
			System.out.println(dbMgr.retrieveDatabaseVersion());
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		
		int documentCount = noticeBoard.getDocumentCount();
		
		noticeBoard.reverseDocumentOrder();
		for (int i=0; i<documentCount; i++)
		{
			System.out.print("insert a XeDocument into the database table ..... ");
			
			Long documentSerial = dbMgr.getXeSequence();
			XeDocument document = noticeBoard.getDocument(i);
			dbMgr.insertXeDocument(noticeBoardModuleSerial, documentSerial, document);
			
			if (document.isAttachedFile())
			{
				for (int j=0; j<document.getAttachedFileCount(); j++)
				{
					fdMgr.fileDownloadIntoLocalDisk(baseHttpUrl, document.getAttachedFile(j), noticeBoardModuleSerial, documentSerial);
					Long fileSerial = dbMgr.getXeSequence();
					dbMgr.insertXeFiles(noticeBoardModuleSerial, documentSerial, fileSerial, document.getAttachedFile(j));
				}
			}
			
			System.out.println("OK [" + (i+1) + " / " + documentCount + "]");
		}
		
		System.out.println();
		
		
		
		
		
		
		/****************************** Finish Phase ******************************/
		
		// the crawling and backup processes are successfully completed
		System.out.println("============================================================================");
		System.out.println("======= the crawling and backup processes are successfully completed =======");
		System.out.println("============================================================================");
		System.out.println("========================== APPLICATION TERMINATED ==========================");
		System.out.println("============================================================================");
		
	}

}
